from fastapi import APIRouter, File, UploadFile, HTTPException, Depends
from fastapi.responses import FileResponse
from core.audio_processor import process_audio, process_audio_async, AudioProcessingError
from utils.file_utils import save_temp_file
from .schemas import (
    AudioProcessingRequest,
    ProcessingResult,
    ErrorResponse,
    AudioMetadata,
    MusicInfo
)
import os
from pathlib import Path
import logging
import time
from typing import Optional, List, Dict
from datetime import datetime
from pydantic import BaseModel
import shutil

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

router = APIRouter()

# 允许的音频文件类型
ALLOWED_EXTENSIONS = {"wav", "mp3", "ogg"}

# 确保输出目录存在
output_dir = Path("output")
output_dir.mkdir(exist_ok=True)

class FileInfo(BaseModel):
    """文件信息模型"""
    filename: str
    size: int
    created_at: datetime
    file_type: str

class HistoryGroup(BaseModel):
    """历史记录分组模型"""
    group_id: str
    created_at: datetime
    files: List[FileInfo]

@router.post("/process", response_model=ProcessingResult, responses={400: {"model": ErrorResponse}, 500: {"model": ErrorResponse}})
async def process_audio_endpoint(
    file: UploadFile = File(...),
    processing_options: Optional[AudioProcessingRequest] = None
):
    """
    处理音频文件并生成乐谱
    
    - **file**: 音频文件（支持wav、mp3、ogg格式）
    - **processing_options**: 处理选项（可选）
        - min_note_duration: 最小音符持续时间
        - tempo_bpm: 速度（每分钟节拍数）
    """
    start_time = time.time()
    temp_path = None
    
    try:
        # 验证文件类型
        file_ext = file.filename.split(".")[-1].lower()
        if file_ext not in ALLOWED_EXTENSIONS:
            raise AudioProcessingError(
                f"不支持的文件类型。仅支持: {', '.join(ALLOWED_EXTENSIONS)}",
                400
            )
        
        logger.info(f"开始处理音频文件: {file.filename}")
        
        # 保存临时文件
        temp_path = save_temp_file(file)
        logger.info(f"临时文件已保存: {temp_path}")
        
        # 使用处理选项
        options = processing_options or AudioProcessingRequest()
        logger.info(f"处理选项: {options.dict()}")
        
        # 处理音频文件
        result = await process_audio_async(
            temp_path,
            tempo_bpm=options.tempo_bpm,
            min_note_duration=options.min_note_duration
        )
        
        # 计算处理时间
        processing_time = time.time() - start_time
        logger.info(f"音频处理完成，耗时: {processing_time:.2f}秒")
        
        # 构建响应
        return ProcessingResult(
            status="success",
            metadata=AudioMetadata(
                duration=result["metadata"]["duration"],
                sample_rate=result["metadata"]["sample_rate"],
                channels=result["metadata"]["channels"],
                format=file_ext,
                file_size=file.size
            ),
            music_info=MusicInfo(
                tempo=result["metadata"]["tempo"],
                notes=result["metadata"]["notes"]
            ),
            output_files=result["output_files"],
            processing_time=processing_time
        )
                
    except AudioProcessingError as e:
        logger.error(f"音频处理错误: {e.message}")
        raise HTTPException(
            status_code=e.error_code,
            detail=ErrorResponse(
                error_code=e.error_code,
                message=e.message
            ).dict()
        )
    except Exception as e:
        logger.error(f"未预期的错误: {str(e)}", exc_info=True)
        raise HTTPException(
            status_code=500,
            detail=ErrorResponse(
                error_code=500,
                message="服务器内部错误",
                details={"error": str(e)}
            ).dict()
        )
    finally:
        # 清理临时文件
        if temp_path and os.path.exists(temp_path):
            try:
                os.remove(temp_path)
                logger.info(f"临时文件已删除: {temp_path}")
            except Exception as e:
                logger.error(f"删除临时文件失败: {str(e)}")

@router.get("/output/{filename}")
async def get_output_file(filename: str):
    """获取生成的文件"""
    try:
        file_path = output_dir / filename
        logger.info(f"请求文件: {file_path}")
        
        if not file_path.exists():
            raise HTTPException(
                status_code=404,
                detail=ErrorResponse(
                    error_code=404,
                    message="文件不存在"
                ).dict()
            )
            
        if not file_path.is_file():
            raise HTTPException(
                status_code=400,
                detail=ErrorResponse(
                    error_code=400,
                    message="无效的文件"
                ).dict()
            )
        
        # 根据文件扩展名设置正确的 MIME 类型
        ext = file_path.suffix.lower()
        mime_types = {
            '.png': 'image/png',
            '.txt': 'text/plain',
            '.mid': 'audio/midi',
            '.midi': 'audio/midi',
            '.musicxml': 'application/vnd.recordare.musicxml+xml',
            '.xml': 'application/vnd.recordare.musicxml+xml',
            '.pdf': 'application/pdf'
        }
        
        media_type = mime_types.get(ext, 'application/octet-stream')
            
        return FileResponse(
            str(file_path),
            media_type=media_type
        )
    except Exception as e:
        logger.error(f"获取文件时出错: {str(e)}")
        raise HTTPException(
            status_code=500,
            detail=ErrorResponse(
                error_code=500,
                message="获取文件时出错",
                details={"error": str(e)}
            ).dict()
        )

@router.get("/history", response_model=List[HistoryGroup])
async def get_history():
    """获取输出文件夹中的文件列表，按批次分组"""
    try:
        # 获取所有文件
        all_files = []
        for file_path in output_dir.glob("*"):
            if file_path.is_file():
                stat = file_path.stat()
                all_files.append(FileInfo(
                    filename=file_path.name,
                    size=stat.st_size,
                    created_at=datetime.fromtimestamp(stat.st_ctime),
                    file_type=file_path.suffix.lower()[1:] if file_path.suffix else "unknown"
                ))
        
        # 按创建时间分组（同一分钟内创建的文件视为同一批次）
        groups: Dict[str, List[FileInfo]] = {}
        for file in all_files:
            # 使用分钟级别的时间戳作为分组ID
            group_id = file.created_at.strftime("%Y%m%d%H%M")
            if group_id not in groups:
                groups[group_id] = []
            groups[group_id].append(file)
        
        # 转换为分组列表
        history_groups = []
        for group_id, files in groups.items():
            # 使用该批次最早的文件创建时间作为批次时间
            created_at = min(file.created_at for file in files)
            history_groups.append(HistoryGroup(
                group_id=group_id,
                created_at=created_at,
                files=sorted(files, key=lambda x: x.created_at, reverse=True)
            ))
        
        # 按批次时间降序排序
        history_groups.sort(key=lambda x: x.created_at, reverse=True)
        return history_groups
    except Exception as e:
        logger.error(f"获取历史记录失败: {str(e)}")
        raise HTTPException(
            status_code=500,
            detail=ErrorResponse(
                error_code=500,
                message="获取历史记录失败",
                details={"error": str(e)}
            ).dict()
        )

@router.delete("/history/{group_id}")
async def delete_history_group(group_id: str):
    """删除指定批次的所有文件"""
    try:
        # 获取该批次的所有文件
        files = []
        for file_path in output_dir.glob("*"):
            if file_path.is_file():
                stat = file_path.stat()
                file_time = datetime.fromtimestamp(stat.st_ctime)
                if file_time.strftime("%Y%m%d%H%M") == group_id:
                    files.append(file_path)
        
        # 删除文件
        for file_path in files:
            try:
                file_path.unlink()
                logger.info(f"删除文件: {file_path}")
            except Exception as e:
                logger.error(f"删除文件失败 {file_path}: {str(e)}")
        
        return {"message": "删除成功"}
    except Exception as e:
        logger.error(f"删除历史记录失败: {str(e)}")
        raise HTTPException(
            status_code=500,
            detail=ErrorResponse(
                error_code=500,
                message="删除历史记录失败",
                details={"error": str(e)}
            ).dict()
        )